package com.nulldev.util.scripting.cup.translators.cup_asm;

import java.util.List;

import com.nulldev.util.JVM.JVM;
import com.nulldev.util.VariableAPI.MathUtil;
import com.nulldev.util.VariableAPI.util.strings.splitters.Splitters;
import com.nulldev.util.data.Arrays.arrays.FastLists;
import com.nulldev.util.scripting.cup.instruction_sets.sil.insts.AddOperation;
import com.nulldev.util.scripting.cup.instruction_sets.sil.insts.CUPIDQuery;
import com.nulldev.util.scripting.cup.instruction_sets.sil.insts.CopyRegister;
import com.nulldev.util.scripting.cup.instruction_sets.sil.insts.DecrementOperation;
import com.nulldev.util.scripting.cup.instruction_sets.sil.insts.DivideOperation;
import com.nulldev.util.scripting.cup.instruction_sets.sil.insts.HaltInstruction;
import com.nulldev.util.scripting.cup.instruction_sets.sil.insts.IncrementOperation;
import com.nulldev.util.scripting.cup.instruction_sets.sil.insts.LoadNearestRegister;
import com.nulldev.util.scripting.cup.instruction_sets.sil.insts.LoadRegister;
import com.nulldev.util.scripting.cup.instruction_sets.sil.insts.ModulusOperation;
import com.nulldev.util.scripting.cup.instruction_sets.sil.insts.MoveRegister;
import com.nulldev.util.scripting.cup.instruction_sets.sil.insts.MultiplyOperation;
import com.nulldev.util.scripting.cup.instruction_sets.sil.insts.PrefetchInstructionOperation;
import com.nulldev.util.scripting.cup.instruction_sets.sil.insts.RegisterTypeOf;
import com.nulldev.util.scripting.cup.instruction_sets.sil.insts.SubtractOperation;
import com.nulldev.util.scripting.cup.instruction_sets.sil.insts.WriteToRegister;
import com.nulldev.util.scripting.cup.instruction_sets.smi.insts.LoadStringRegister;
import com.nulldev.util.scripting.cup.instruction_sets.sti.insts.ConsoleOut;
import com.nulldev.util.scripting.cup.instructions.CupInstruction;
import com.nulldev.util.scripting.cup.vee.VEE;
import com.nulldev.util.scripting.cup.vee.CUPRegister.CUPRegisterType;
import com.nulldev.util.scripting.cup.vee.runner.CUPRunner;

public class CUPASMReader {

	private static final CupInstruction NULL = new CupInstruction() {

		@Override
		public int getInstructionID() {
			return 0;
		}

		@Override
		public int getInstructionArgumentsCount() {
			return 0;
		}

		@Override
		public Object[] getInstructionArguments() {
			return new Object[0];
		}

		@Override
		public String getDisplayableInstructionName() {
			return "NULL";
		}

		@Override
		public String[] getDefaultInstructionArguments() {
			return new String[0];
		}
	};

	public static CupInstruction translate(final String line) {
		if (line == null || line.isEmpty())
			return NULL;
		final String[] segments = Splitters.byPattern(line, "\\W+").splitToArray(line);
		if (segments == null || segments.length == 0 || segments[0].startsWith("//") || segments[0].startsWith("#"))
			return NULL;
		final String inst_name = segments[0];
		final String arg1 = segments.length >= 2 ? segments[1] : null;
		final String arg2 = segments.length >= 3 ? segments[2] : null;
		final String arg3 = segments.length >= 4 ? segments[3] : null;
		switch (inst_name) {
			case "LNR":
				return new LoadNearestRegister(arg1);
			case "LRG":
				return new LoadRegister(arg1, arg2);
			case "LSR":
				return new LoadStringRegister(arg1, arg2);
			case "HLT":
				return new HaltInstruction();
			case "ADD":
				return new AddOperation(arg1, arg2, arg3);
			case "SUB":
				return new SubtractOperation(arg1, arg2, arg3);
			case "MUL":
				return new MultiplyOperation(arg1, arg2, arg3);
			case "DIV":
				return new DivideOperation(arg1, arg2, arg3);
			case "MOV":
				return new MoveRegister(arg1, arg2);
			case "CPY":
				return new CopyRegister(arg1, arg2);
			case "CUPID":
				return new CUPIDQuery(arg1, arg2);
			case "MOD":
				return new ModulusOperation(arg1, arg2);
			case "INC":
				return new IncrementOperation(arg1, arg2);
			case "DEC":
				return new DecrementOperation(arg1, arg2);
			case "PFCH":
				return new PrefetchInstructionOperation(arg1);
			case "REGTF":
				return new RegisterTypeOf(arg1, arg2);
			case "COUT":
				return new ConsoleOut(arg1);
			case "WTR":
				return new WriteToRegister(arg1, arg2);
			default:
				return NULL;
		}
	}

	public static void main(String[] args) {
		final String payload = "LNR a\n" + "INC a, 5\n" + "LNR b\n" + "PFCH b\n" + "ADD a, 5\n" + "MUL a, 3";
		final List<CupInstruction> insts = FastLists.list();
		for (final String line : Splitters.splitString(payload, "\n")) {
			final CupInstruction inst = translate(line);
			JVM.println(inst);
			insts.add(inst);
		}
		final VEE vee = new VEE(CUPRegisterType.NORMAL);
		new CUPRunner(vee, insts).run();
		JVM.println("-> Execution finished, dumping registers.");
		vee.getRegisterManager().asMap().entrySet().forEach((e) -> {
			Object val = e.getValue();
			if (val instanceof Integer)
				val = MathUtil.intToHexStr((int) val);
			else if (val instanceof Short)
				val = MathUtil.intToHexStr((short) val);
			JVM.println(e.getKey() + " = " + val);
		});
	}

}
